home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / serverlib.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  9KB  |  405 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.    This is free software distributed under the terms of the
  3.    GNU Public License.  See the file COPYING for details.
  4.  
  5.    $Id: serverlib.c,v 1.36 2001/02/15 08:39:45 drscholl Exp $ */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #ifndef WIN32
  11. #include <unistd.h>
  12. #endif
  13. #include "opennap.h"
  14. #include "debug.h"
  15.  
  16. void
  17. send_cmd (CONNECTION * con, unsigned int msgtype, const char *fmt, ...)
  18. {
  19.     va_list ap;
  20.     size_t  l;
  21.  
  22.     va_start (ap, fmt);
  23.     vsnprintf (Buf + 4, sizeof (Buf) - 4, fmt, ap);
  24.     va_end (ap);
  25.  
  26.     set_tag (Buf, msgtype);
  27.     l = strlen (Buf + 4);
  28.     set_len (Buf, l);
  29.     queue_data (con, Buf, 4 + l);
  30. }
  31.  
  32. /* wrapper for pass_message() */
  33. void
  34. pass_message_args (CONNECTION * con, u_int msgtype, const char *fmt, ...)
  35. {
  36.     va_list ap;
  37.     size_t  l;
  38.  
  39.     if (!Servers)
  40.     return;            /* nothing to do */
  41.  
  42.     va_start (ap, fmt);
  43.     vsnprintf (Buf + 4, sizeof (Buf) - 4, fmt, ap);
  44.     va_end (ap);
  45.     set_tag (Buf, msgtype);
  46.     l = strlen (Buf + 4);
  47.     set_len (Buf, l);
  48.     pass_message (con, Buf, 4 + l);
  49. }
  50.  
  51. /* this function sends a command to an arbitrary user without the caller
  52.    needing to know if its a local client or not */
  53. void
  54. send_user (USER * user, int tag, char *fmt, ...)
  55. {
  56.     int     len, offset;
  57.     va_list ap;
  58.  
  59.     if (user->local)
  60.     {
  61.     /* deliver directly */
  62.     va_start (ap, fmt);
  63.     vsnprintf (Buf + 4, sizeof (Buf) - 4, fmt, ap);
  64.     va_end (ap);
  65.     set_tag (Buf, tag);
  66.     len = strlen (Buf + 4);
  67.     set_len (Buf, len);
  68.     }
  69.     else
  70.     {
  71.     /* encapsulate and send to remote server */
  72.     snprintf (Buf + 4, sizeof (Buf) - 4, ":%s %s ", Server_Name,
  73.           user->nick);
  74.     offset = strlen (Buf + 4);
  75.     set_tag (Buf, MSG_SERVER_ENCAPSULATED);
  76.     va_start (ap, fmt);
  77.     vsnprintf (Buf + 8 + offset, sizeof (Buf) - 8 - offset, fmt, ap);
  78.     va_end (ap);
  79.     set_tag (Buf + 4 + offset, tag);
  80.     len = strlen (Buf + 8 + offset);
  81.     set_len (Buf + 4 + offset, len);
  82.     len += offset + 4;
  83.     set_len (Buf, len);
  84.     }
  85.     queue_data (user->con, Buf, len + 4);
  86. }
  87.  
  88. /* no such user */
  89. void
  90. nosuchuser (CONNECTION * con)
  91. {
  92.     ASSERT (validate_connection (con));
  93.     if (ISUSER (con))
  94.     send_cmd (con, MSG_SERVER_NOSUCH, "User is not currently online.");
  95. }
  96.  
  97. void
  98. permission_denied (CONNECTION * con)
  99. {
  100.     ASSERT (validate_connection (con));
  101.     if (ISUSER (con))
  102.     send_cmd (con, MSG_SERVER_NOSUCH, "permission denied");
  103. }
  104.  
  105. /* send a message to all peer servers.  `con' is the connection the message
  106.    was received from and is used to avoid sending the message back from where
  107.    it originated. */
  108. void
  109. pass_message (CONNECTION * con, char *pkt, size_t pktlen)
  110. {
  111.     LIST   *list;
  112.  
  113.     for (list = Servers; list; list = list->next)
  114.     if (list->data != con)
  115.         queue_data (list->data, pkt, pktlen);
  116. }
  117.  
  118. /* destroys memory associated with the CHANNEL struct.  this is usually
  119.    not called directly, but in association with the hash_remove() and
  120.    hash_destroy() calls */
  121. void
  122. free_channel (CHANNEL * chan)
  123. {
  124.     ASSERT (validate_channel (chan));
  125.     FREE (chan->name);
  126.     if (chan->topic)
  127.     FREE (chan->topic);
  128.     ASSERT (chan->users == 0);
  129.     list_free (chan->users, 0);
  130.     list_free (chan->bans, (list_destroy_t) free_ban);
  131.     ASSERT (chan->invited == 0);
  132.     list_free (chan->invited, 0);    /* free invite list */
  133.     FREE (chan);
  134. }
  135.  
  136. #ifdef DEBUG
  137. int
  138. validate_connection (CONNECTION * con)
  139. {
  140.     /* does not work with mempool */
  141.     ASSERT_RETURN_IF_FAIL (VALID_LEN (con, sizeof (CONNECTION)), 0);
  142.     ASSERT_RETURN_IF_FAIL (con->magic == MAGIC_CONNECTION, 0);
  143.     ASSERT_RETURN_IF_FAIL ((con->class == CLASS_USER) ^ (con->user == 0), 0);
  144.     ASSERT_RETURN_IF_FAIL (VALID_STR (con->host), 0);
  145.     if (con->sendbuf)
  146.     ASSERT_RETURN_IF_FAIL (buffer_validate (con->sendbuf), 0);
  147.     if (con->recvbuf)
  148.     ASSERT_RETURN_IF_FAIL (buffer_validate (con->recvbuf), 0);
  149.     if (ISUSER (con))
  150.     {
  151.     if (con->uopt)
  152.     {
  153.         ASSERT_RETURN_IF_FAIL (VALID_LEN (con->uopt, sizeof (USEROPT)),
  154.                    0);
  155.         ASSERT_RETURN_IF_FAIL (list_validate (con->uopt->hotlist), 0);
  156.     }
  157.     }
  158.     return 1;
  159. }
  160.  
  161. int
  162. validate_user (USER * user)
  163. {
  164.     /* this doesn't work with the mempool since it is an offset into
  165.        a preallocated chunk */
  166.     ASSERT_RETURN_IF_FAIL (VALID_LEN (user, sizeof (USER)), 0);
  167.     ASSERT_RETURN_IF_FAIL (user->magic == MAGIC_USER, 0);
  168.     ASSERT_RETURN_IF_FAIL (VALID_STR (user->nick), 0);
  169.     ASSERT_RETURN_IF_FAIL (VALID_STR (user->clientinfo), 0);
  170.     ASSERT_RETURN_IF_FAIL (user->con == 0
  171.                || VALID_LEN (user->con, sizeof (CONNECTION)), 0);
  172.     ASSERT_RETURN_IF_FAIL (list_validate (user->channels), 0);
  173.     return 1;
  174. }
  175.  
  176. int
  177. validate_channel (CHANNEL * chan)
  178. {
  179.     ASSERT_RETURN_IF_FAIL (VALID_LEN (chan, sizeof (CHANNEL)), 0);
  180.     ASSERT_RETURN_IF_FAIL (chan->magic == MAGIC_CHANNEL, 0);
  181.     ASSERT_RETURN_IF_FAIL (VALID_STR (chan->name), 0);
  182.     ASSERT_RETURN_IF_FAIL (list_validate (chan->users), 0);
  183.     return 1;
  184. }
  185. #endif
  186.  
  187. /* like pop_user(), but allows `nick' to be another server */
  188. int
  189. pop_user_server (CONNECTION * con, int tag, char **pkt, char **nick,
  190.          USER ** user)
  191. {
  192.     if (ISSERVER (con))
  193.     {
  194.     if (**pkt != ':')
  195.     {
  196.         log
  197.         ("pop_user_server: (tag %d) server message missing sender (from %s)",
  198.          tag, con->host);
  199.         return -1;
  200.     }
  201.     (*pkt)++;
  202.     *nick = next_arg (pkt);
  203.     if (!is_server (*nick))
  204.     {
  205.         *user = hash_lookup (Users, *nick);
  206.         if (!*user)
  207.         {
  208.         log
  209.             ("pop_user_server: (tag %d) could not find user %s (from %s)",
  210.              tag, *nick, con->host);
  211.         return -1;
  212.         }
  213.     }
  214.     else
  215.         *user = 0;
  216.     }
  217.     else
  218.     {
  219.     ASSERT (ISUSER (con));
  220.     *user = con->user;
  221.     *nick = (*user)->nick;
  222.     }
  223.     return 0;
  224. }
  225.  
  226. int
  227. pop_user (CONNECTION * con, char **pkt, USER ** user)
  228. {
  229.     ASSERT (validate_connection (con));
  230.     ASSERT (pkt != 0 && *pkt != 0);
  231.     ASSERT (user != 0);
  232.     if (ISSERVER (con))
  233.     {
  234.     char   *ptr;
  235.  
  236.     if (**pkt != ':')
  237.     {
  238.         log ("pop_user: server message did not contain nick: %s", *pkt);
  239.         return -1;
  240.     }
  241.     ++*pkt;
  242.     ptr = next_arg (pkt);
  243.     *user = hash_lookup (Users, ptr);
  244.     if (!*user)
  245.     {
  246.         log ("pop_user: could not find user %s", ptr);
  247.         return -1;
  248.     }
  249.  
  250.     /* this should not return a user who is local to us.  if so, it
  251.        means that some other server has passed us back a message we
  252.        sent to them */
  253.     if ((*user)->local)
  254.     {
  255.         log ("pop_user: error, received server message for local user!");
  256.         return -1;
  257.     }
  258.     }
  259.     else
  260.     {
  261.     ASSERT (con->class == CLASS_USER);
  262.     ASSERT (con->user != 0);
  263.     *user = con->user;
  264.     }
  265.     return 0;
  266.  
  267. }
  268.  
  269. void
  270. unparsable (CONNECTION * con)
  271. {
  272.     ASSERT (validate_connection (con));
  273.     if (ISUSER (con))
  274.     send_cmd (con, MSG_SERVER_NOSUCH, "parameters are unparsable");
  275. }
  276.  
  277. void
  278. nosuchchannel (CONNECTION * con)
  279. {
  280.     ASSERT (validate_connection (con));
  281.     if (ISUSER (con))
  282.     send_cmd (con, MSG_SERVER_NOSUCH, "no such channel");
  283. }
  284.  
  285. /* returns nonzero if `s' is the name of a server */
  286. int
  287. is_server (const char *s)
  288. {
  289.     LIST   *list;
  290.     CONNECTION *con;
  291.     LINK   *link;
  292.  
  293.     for (list = Servers; list; list = list->next)
  294.     {
  295.     con = list->data;
  296.     if (!strcasecmp (s, con->host))
  297.         return 1;
  298.     }
  299.     for (list = Server_Links; list; list = list->next)
  300.     {
  301.     link = list->data;
  302.     if (!strcasecmp (s, link->server) || !strcasecmp (s, link->peer))
  303.         return 1;
  304.     }
  305.     return 0;
  306. }
  307.  
  308. /* returns nonzero if `nick' is in list `ignore' */
  309. int
  310. is_ignoring (LIST * ignore, const char *nick)
  311. {
  312.     for (; ignore; ignore = ignore->next)
  313.     if (!strcasecmp (nick, ignore->data))
  314.         return 1;
  315.     return 0;
  316. }
  317.  
  318. void
  319. invalid_channel_msg (CONNECTION * con)
  320. {
  321.     ASSERT (validate_connection (con));
  322.     if (ISUSER (con))
  323.     send_cmd (con, MSG_SERVER_NOSUCH, "invalid channel");
  324. }
  325.  
  326. void
  327. truncate_reason (char *s)
  328. {
  329.     if (Max_Reason > 0 && strlen (s) > (unsigned) Max_Reason)
  330.     *(s + Max_Reason) = 0;
  331. }
  332.  
  333. void
  334. invalid_nick_msg (CONNECTION * con)
  335. {
  336.     if (ISUSER (con))
  337.     send_cmd (con, MSG_SERVER_NOSUCH, "invalid nickname");
  338. }
  339.  
  340. CONNECTION *
  341. new_connection (void)
  342. {
  343.     CONNECTION *c = CALLOC (1, sizeof (CONNECTION));
  344.  
  345.     if (!c)
  346.     {
  347.     OUTOFMEMORY ("new_connection");
  348.     return 0;
  349.     }
  350. #ifdef DEBUG
  351.     c->magic = MAGIC_CONNECTION;
  352. #endif
  353.     return c;
  354. }
  355.  
  356. static int
  357. vform_message (char *d, int dsize, int tag, const char *fmt, va_list ap)
  358. {
  359.     int     len;
  360.  
  361.     vsnprintf (d + 4, dsize - 4, fmt, ap);
  362.     len = strlen (d + 4);
  363.     set_tag (d, tag);
  364.     set_len (d, len);
  365.     return (len + 4);
  366. }
  367.  
  368. int
  369. form_message (char *d, int dsize, int tag, const char *fmt, ...)
  370. {
  371.     va_list ap;
  372.     int     len;
  373.  
  374.     va_start (ap, fmt);
  375.     len = vform_message (d, dsize, tag, fmt, ap);
  376.     va_end (ap);
  377.     return len;
  378. }
  379.  
  380. void
  381. send_cmd_pre (CONNECTION * con, unsigned int tag, const char *prefix,
  382.           const char *fmt, ...)
  383. {
  384.     va_list ap;
  385.     int     len;
  386.  
  387.     va_start (ap, fmt);
  388.     /* if the user's client supports use of real numerics send the raw */
  389.     if (con->numerics)
  390.     len = vform_message (Buf, sizeof (Buf), tag, fmt, ap);
  391.     else
  392.     {
  393.     /*otherwise prefix it with a descriptive string and send it as a 404 */
  394.     strncpy (Buf + 4, prefix, sizeof (Buf) - 4);
  395.     len = strlen (Buf + 4);
  396.     vsnprintf (Buf + 4 + len, sizeof (Buf) - 4 - len, fmt, ap);
  397.     len += strlen (Buf + 4 + len);
  398.     set_tag (Buf, MSG_SERVER_NOSUCH);
  399.     set_len (Buf, len);
  400.     len += 4;
  401.     }
  402.     queue_data (con, Buf, len);
  403.     va_end (ap);
  404. }
  405.